package com.example.app.service;

import com.example.app.config.DeepSeekConfig;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.netty.channel.ChannelOption;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;

import java.time.Duration;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

@Service
public class DeepSeekClient {

    // 正确的超时时间（单位为秒）
    private static final int CONNECT_TIMEOUT_SECONDS = 60;    // 连接超时60秒
    private static final int RESPONSE_TIMEOUT_SECONDS = 240;  // 响应超时4分钟

    private final WebClient webClient;
    private final DeepSeekConfig config;
    private final ObjectMapper objectMapper;

    public DeepSeekClient(WebClient.Builder webClientBuilder,
                          DeepSeekConfig config,
                          ObjectMapper objectMapper) {
        this.config = config;
        this.objectMapper = objectMapper;

        // 配置 Netty HTTP 客户端超时设置（单位修复）
        HttpClient httpClient = HttpClient.create()
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, CONNECT_TIMEOUT_SECONDS * 1000)
                .responseTimeout(Duration.ofSeconds(100000))
                .doOnConnected(conn -> conn
                        .addHandlerLast(new ReadTimeoutHandler(RESPONSE_TIMEOUT_SECONDS, TimeUnit.SECONDS))
                        .addHandlerLast(new WriteTimeoutHandler(RESPONSE_TIMEOUT_SECONDS, TimeUnit.SECONDS))
                );

        this.webClient = webClientBuilder
                .baseUrl(config.getBaseUrl())
                .clientConnector(new ReactorClientHttpConnector(httpClient))
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                .defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer " + config.getApiKey())
                .build();
    }

    public Mono<String> getResponse(String prompt) {
        ObjectNode requestBody = objectMapper.createObjectNode();
        requestBody.put("model", config.getModelName());
        requestBody.put("temperature", config.getTemperature());
        requestBody.put("max_tokens", 65536);

        ObjectNode messageNode = requestBody.putArray("messages").addObject();
        messageNode.put("role", "user");
        messageNode.put("content", prompt);

        return webClient.post()
                .uri("/chat/completions")
                .bodyValue(requestBody)
                .exchangeToMono(response -> {
                    if (response.statusCode().is5xxServerError()) {
                        return response.bodyToMono(String.class)
                                .flatMap(errorBody -> Mono.error(new ServerException("DeepSeek API服务器错误: " + errorBody)));
                    }
                    if (response.statusCode() == HttpStatus.TOO_MANY_REQUESTS) {
                        return Mono.error(new RateLimitException("请求过于频繁，请稍后再试"));
                    }
                    if (response.statusCode().is4xxClientError()) {
                        return response.bodyToMono(String.class)
                                .flatMap(errorBody -> Mono.error(new ClientException("请求参数错误: " + errorBody)));
                    }

                    return response.bodyToMono(ObjectNode.class)
                            .timeout(Duration.ofSeconds(RESPONSE_TIMEOUT_SECONDS), Mono.just(createTimeoutResponse()));
                })
                .flatMap(this::parseApiResponse)
                .onErrorResume(this::handleApiError);
    }
    private ObjectNode createTimeoutResponse() {
        ObjectNode response = objectMapper.createObjectNode();
        ObjectNode choice = objectMapper.createObjectNode();
        ObjectNode message = objectMapper.createObjectNode();

        message.put("content", "服务响应超时，建议简化您的问题或稍后重试");
        choice.set("message", message);
        response.putArray("choices").add(choice);

        return response;
    }

    private Mono<String> parseApiResponse(ObjectNode response) {
        if (response != null &&
                response.has("choices") &&
                response.get("choices").size() > 0 &&
                response.get("choices").get(0).has("message") &&
                response.get("choices").get(0).get("message").has("content")) {

            return Mono.just(response.get("choices")
                    .get(0)
                    .get("message")
                    .get("content")
                    .asText());
        }
        return Mono.just("未获取到有效的回复");
    }

    private Mono<String> handleApiError(Throwable e) {
        if (e instanceof ServerException) {
            return Mono.just("服务器错误: " + e.getMessage());
        } else if (e instanceof RateLimitException) {
            return Mono.just("请求受限: " + e.getMessage());
        } else if (e instanceof ClientException) {
            return Mono.just("请求错误: " + e.getMessage());
        } else if (e instanceof java.util.concurrent.TimeoutException) {
            return Mono.just("请求超时: 超过" + RESPONSE_TIMEOUT_SECONDS + "秒未收到响应");
        }
        return Mono.just("API请求失败: " + e.getClass().getSimpleName() + " - " + e.getMessage());
    }

    private static class ServerException extends RuntimeException {
        public ServerException(String message) { super(message); }
    }

    private static class RateLimitException extends RuntimeException {
        public RateLimitException(String message) { super(message); }
    }

    private static class ClientException extends RuntimeException {
        public ClientException(String message) { super(message); }
    }
}
